package main

import (
	"errors"
	"fmt"
	"github.com/corona10/goimagehash/transforms"
	"image"
	"image/color"
	"image/draw"
	"image/jpeg"
	"math"
	"os"
	"strconv"
	"time"
)
type BestMatch struct {
	x int
	y int
}

func main() {
	file1, _ := os.Open(".\\img\\a1.jpg")
	file2, _ := os.Open(".\\img\\location.jpg")
	defer file1.Close()
	defer file2.Close()

	img1, _ := jpeg.Decode(file1)
	img2, _ := jpeg.Decode(file2)
	bgWidth,bgHigh,lWidth,lHigh := img1.Bounds().Dx(),img1.Bounds().Dy(),img2.Bounds().Dx(),img2.Bounds().Dy()
	
	var bgpixels,pixels [][]float64 = transforms.Rgb2Gray(img1),transforms.Rgb2Gray(img2)
	var distanceGray  int
	var gap float64 = 0		//允许像素点差值 0.0169999999999959-0.359000000000001 之间含，难以分辨
	note ,notes  := BasicPoint(bgpixels,pixels,bgWidth,bgHigh,lWidth,lHigh,gap)		//求完全匹配小图四个顶点坐标，无完全匹配选择最佳

	b := img1.Bounds()
	m := image.NewRGBA(b)
	draw.Draw(m, b, img1, b.Min, draw.Over)
	if len(notes) == 0 {
		distanceGray = FullQuery(bgpixels,pixels,note.x,note.y,lWidth,lHigh,0.5) //这里设置固定值 允许灰度值最大误差为0.5
		Rectangle(note.x,note.y,4,note.x+lWidth,note.y+lHigh,m)		//找到最佳坐标后，框出
	}





	distance := ContrastImg(note.x,note.y,lWidth,lHigh,img1,img2)
	//imgType := img1.ColorModel()  //

	nameImg := strconv.Itoa(int(time.Now().Unix()))
	imgw, err := os.Create(nameImg + "shuidaan.jpg")
	if err != nil {
		fmt.Println(err)
	}
	jpeg.Encode(imgw, m, &jpeg.Options{100})
	defer imgw.Close()
	//fmt.Println(distance,"22",&imgType,notes,distanceGray,float64(distanceGray)/(float64(lWidth)*float64(lHigh)))
	fmt.Println(distance, float64(lWidth*lHigh),100-float64(distance)/(float64(lWidth*lHigh)))
	fmt.Printf("彩色对比方式有%d 块不同，相似性为 %f。灰度对比方式有%d 块不同，相似性为%f ",distance,1-float64(distance)/(float64(lWidth*lHigh)),distanceGray,1-float64(distanceGray)/(float64(lWidth*lHigh)))
}

//若灰度值有多个匹配，则再进行逐个像素rgba匹配，求最佳.有完全相同和允许色差对比两种方式
func ContrastImg(bgWidthStart,bgHighEnd,lWidth,lHigh int,bgImg,lImg image.Image) int {
	var temp int = 0
	var gap float64  = 615  //500~ 625 在这个范围内，处理的结果与灰度值类似
	for i:= 0; i <= lWidth ; i++ {
		for j:=0; j <= lHigh ; j++  {
			//完全匹配对应像素点，否则计为不同
			//if bgImg.At(bgWidthStart+i,bgHighEnd+j) != lImg.At(i,j) {
			//	temp ++
			//}
			//彩色三原色逐个对比色差,可以设置允许色差gap 调整相似性
			br,bg,bb ,_ := bgImg.At(bgWidthStart+i,bgHighEnd+j).RGBA() //58082 57730 59897
			r,g,b,_ := lImg.At(i,j).RGBA()								//58082 57642 60351
			if math.Abs(float64(r) - float64(br)) > gap || math.Abs(float64(g) - float64(bg)) > gap || math.Abs(float64(b)-float64(bb)) > gap {
				temp ++
			}
		}
	}
	return temp
}
func CropImgs(src image.Image, x, y, w, h int) (image.Image, error) {

	var subImg image.Image

	if rgbImg, ok := src.(*image.YCbCr); ok {
		subImg = rgbImg.SubImage(image.Rect(x, y, x+w, y+h)).(*image.YCbCr) //图片裁剪x0 y0 x1 y1
	} else if rgbImg, ok := src.(*image.RGBA); ok {
		subImg = rgbImg.SubImage(image.Rect(x, y, x+w, y+h)).(*image.RGBA) //图片裁剪x0 y0 x1 y1
	} else if rgbImg, ok := src.(*image.NRGBA); ok {
		subImg = rgbImg.SubImage(image.Rect(x, y, x+w, y+h)).(*image.NRGBA) //图片裁剪x0 y0 x1 y1
	} else {

		return subImg, errors.New("图片解码失败")
	}

	return subImg, nil
}
//四个角对比，减少全图扫描计算量
func BasicPoint(bgpixels, pixels [][]float64, bgWidth, bgHigh, lWidth, lHigh int, gap float64) (BestMatch, map[int]int) {
	//pixels 先h高，再w宽 转换方式决定
	distance,temp := 9999,0
	var alike,tempAxis, axis1, axis2, axis3, axis4 float64 = 9999999,999999,0,0,0,0  //alike最相似，tempAxis最小坐标差值，axis坐标差值1,2,3,4
	notes := make(map[int]int)	//记录最佳位置匹配
	var note BestMatch			//记录最佳位置匹配
	for h := 0; h < bgHigh - lHigh ; h++ {
		for w := 0 ; w < bgWidth - lWidth ; w++ {
			axis1, axis2, axis3, axis4 = math.Abs( bgpixels[h][w] - pixels[0][0]), math.Abs(bgpixels[h][w+lWidth-1] - pixels[0][lWidth-1]),
				math.Abs(bgpixels[h+lHigh-1][w] - pixels[lHigh-1][0]), math.Abs(bgpixels[h+lHigh-1][w+lWidth-1] - pixels[lHigh-1][lWidth-1])
			tempAxis = axis1 + axis2 + axis3 + axis4
			if alike > tempAxis {
				alike = tempAxis
				note.y,note.x = h,w
			}
			if axis1 > gap || axis2 > gap || axis3 > gap || axis4 > gap {
				continue
			}
			fmt.Println(distance)
			temp = FullQuery(bgpixels,pixels,w,h,lWidth,lHigh,gap)
			if distance >= temp {
				note.x, note.y = w,h 	//记录最佳位置匹配
				notes[h]=w				//记录符合条件匹配位置，未优化。实际上只匹配了刚开始符合条件的值，到达最佳匹配后，只匹配与最佳匹配相等的
			}
		}
	}
	//fmt.Println(alike ,note.x,note.y)
	return note,notes
}
//灰度级逐个像素对比 ，返回误差数量，及最小误差数量
func FullQuery(bgpixels, pixels [][]float64, startW, startH, Width, High int, gap float64) int {
	distance := 0
	for h := 0 ; h < High ; h++  {
		for w := 0 ; w < Width ; w++ {
			if bgpixels[h+startH][w+startW] - pixels[h][w] > gap {
				distance++
			}
		}
	}
	return distance
}
//框出匹配图像的位置
func Rectangle(x, y, size, endx, endy int, m *image.RGBA) error {
	//x,y划线起点坐标  size线粗  dire线方向 endx, endy结束坐标
		for dot := 0;dot < size;dot++ {
			for z:= y;z < endy ;z++  {
				m.Set(x-dot,z,color.RGBA{255, 0, 0, 255})
			}
		}//左
		for dot := 0;dot < size;dot++ {
			for z:= y;z < endy ;z++  {
				m.Set(endx+dot,z,color.RGBA{0, 255, 0, 255})
			}
		}//右
		for dot := 0;dot < size;dot++ {
			for z:= x;z < endx ;z++  {
				m.Set(z,y-dot,color.RGBA{255, 0, 0, 255})
			}
		}//上
		for dot := 0;dot < size;dot++ {
			for z:= x;z < endx ;z++  {
				m.Set(z,endy+dot,color.RGBA{0, 255, 0, 255})
			}
		}//下

	return nil
}